/**
 * BodyLang 绘图工具库
 * 包含所有绘制图形的方法
 */

// 定义点的接口
interface Point {
  x: number
  y: number
}

// 应用缩放比例到点坐标
function applyScale(point: Point, scale: number): Point {
  return {
    x: point.x * scale,
    y: point.y * scale,
  }
}

/**
 * 绘制矩形框
 * @param ctx Canvas上下文
 * @param s 左上角点 {x, y}
 * @param e 右下角点 {x, y}
 * @param b 边框粗度
 * @param c 边框颜色
 * @param scale 缩放比例，默认为1
 */
export function drawFrame(ctx: any, s: Point, e: Point, b: number, c: string, scale: number = 1) {
  // 应用缩放
  const scaledS = applyScale(s, scale)
  const scaledE = applyScale(e, scale)

  ctx.setLineDash([0, 0], 0)
  ctx.beginPath()
  if (b == 0) {
    ctx.setFillStyle(c)
    ctx.fillRect(scaledS.x, scaledS.y, scaledE.x - scaledS.x, scaledE.y - scaledS.y)
  } else {
    ctx.strokeStyle = c
    ctx.LineWidth = b
    ctx.strokeRect(scaledS.x, scaledS.y, scaledE.x - scaledS.x, scaledE.y - scaledS.y)
  }
  ctx.closePath()
}

/**
 * 绘制线段
 * @param ctx Canvas上下文
 * @param s 起点 {x, y}
 * @param e 结束点 {x, y}
 * @param b 线段粗度
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawLine(
  ctx: any,
  s: Point,
  e: Point,
  b: number,
  c: string,
  scale: number = 1,
  c1?: string,
) {
  // 应用缩放
  const scaledS = applyScale(s, scale)
  const scaledE = applyScale(e, scale)

  ctx.setLineDash([0, 0], 0)
  ctx.beginPath()
  ctx.LineWidth = b

  if (c1) {
    // 使用渐变色
    const gradient = ctx.createLinearGradient(scaledS.x, scaledS.y, scaledE.x, scaledE.y)
    gradient.addColorStop(0, c)
    gradient.addColorStop(1, c1)
    ctx.strokeStyle = gradient
  } else {
    ctx.strokeStyle = c
  }

  ctx.moveTo(scaledS.x, scaledS.y)
  ctx.lineTo(scaledE.x, scaledE.y)
  ctx.stroke()
  ctx.closePath()
}

/**
 * 绘制虚线
 * @param ctx Canvas上下文
 * @param s 起点 {x, y}
 * @param e 结束点 {x, y}
 * @param b 线段粗度
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawDashed(
  ctx: any,
  s: Point,
  e: Point,
  b: number,
  d: Array<number> = [2, 2],
  c: string,
  c1?: string,
  scale: number = 1,
) {
  // 应用缩放
  const scaledS = applyScale(s, scale)
  const scaledE = applyScale(e, scale)

  ctx.beginPath()
  ctx.LineWidth = b
  ctx.setLineDash(d, 0) // 设置虚线样式，线段长度5，间隙长度5

  if (c1) {
    // 使用渐变色
    const gradient = ctx.createLinearGradient(scaledS.x, scaledS.y, scaledE.x, scaledE.y)
    gradient.addColorStop(0, c)
    gradient.addColorStop(1, c1)
    ctx.strokeStyle = gradient
  } else {
    ctx.strokeStyle = c
  }

  ctx.moveTo(scaledS.x, scaledS.y)
  ctx.lineTo(scaledE.x, scaledE.y)
  ctx.stroke()
  ctx.closePath()
  ctx.setLineDash([0, 0], 0) // 重置虚线样式
}

/**
 * 绘制直线箭头（等边三角形）
 * @param ctx Canvas上下文
 * @param s 起点 {x, y}
 * @param e 结束点 {x, y}
 * @param size 箭头大小（影响等边三角形的大小）
 * @param b 线段粗度
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawArrow(
  ctx: any,
  s: Point,
  e: Point,
  size: number,
  b: number,
  c: string,
  c1?: string,
  scale: number = 1,
) {
  // 计算线条角度
  const angle = Math.atan2(e.y - s.y, e.x - s.x) // 线条的角度（弧度）

  // 等边三角形的默认高度
  const defaultHeight = 10

  // 使用size参数调整三角形大小，但保持等边三角形的比例
  const arrowHeight = defaultHeight * (size / 10) // 根据size参数调整高度

  // 等边三角形的边长 = 高度 * (2/√3)
  const sqrt3 = Math.sqrt(3)
  const sideLength = arrowHeight * (2 / sqrt3)

  // 计算箭头尖端位置（在线条终点的延长线上）
  const tipExtension = arrowHeight // 箭头尖端延伸的距离
  const tipPoint = {
    x: e.x + Math.cos(angle) * tipExtension,
    y: e.y + Math.sin(angle) * tipExtension,
  }

  // 绘制线段（从起点到终点）
  drawLine(ctx, s, e, b, c, c1, scale)

  // 应用缩放
  const scaledTip = applyScale(tipPoint, scale) // 箭头尖端
  const scaledE = applyScale(e, scale) // 箭头基点（线段终点）

  // 计算等边三角形的底边两个顶点
  // 计算底边方向（与线段垂直）
  const baseAngle = angle + Math.PI / 2 // 垂直于线段方向

  // 计算底边两端点（等边三角形的底边长度为sideLength）
  const halfSideLength = (sideLength * scale) / 2

  // 计算底边两个顶点（以终点为基准）
  const leftBaseX = scaledE.x + Math.cos(baseAngle) * halfSideLength
  const leftBaseY = scaledE.y + Math.sin(baseAngle) * halfSideLength
  const rightBaseX = scaledE.x - Math.cos(baseAngle) * halfSideLength
  const rightBaseY = scaledE.y - Math.sin(baseAngle) * halfSideLength

  // 绘制箭头（等边三角形）
  ctx.beginPath()
  ctx.setFillStyle(c1 || c) // 使用渐变色或主色

  ctx.moveTo(scaledTip.x, scaledTip.y) // 箭头尖端
  ctx.lineTo(leftBaseX, leftBaseY) // 底边左侧点
  ctx.lineTo(rightBaseX, rightBaseY) // 底边右侧点
  ctx.closePath()
  ctx.fill()
}

/**
 * 绘制放射点
 * @param ctx Canvas上下文
 * @param x 圆心坐标X
 * @param y 圆心坐标Y
 * @param r 半径
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawJoint(
  ctx: any,
  x: number,
  y: number,
  r: number,
  c: string,
  c1?: string,
  scale: number = 1,
) {
  // 应用缩放
  const scaledX = x * scale
  const scaledY = y * scale
  const scaledR = r * scale

  ctx.setLineDash([0, 0], 0)
  ctx.beginPath()

  const grd = ctx.createRadialGradient(scaledX, scaledY, scaledR)
  grd.addColorStop(0, c)
  grd.addColorStop(1, c1 || c)
  ctx.setFillStyle(grd)

  ctx.arc(scaledX, scaledY, scaledR, 0, 2 * Math.PI)
  ctx.fill()
  ctx.closePath()
}

/**
 * 绘制圆
 * @param ctx Canvas上下文
 * @param x 圆心坐标X
 * @param y 圆心坐标Y
 * @param r 半径
 * @param b 边线粗度
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawCircle(
  ctx: any,
  x: number,
  y: number,
  r: number,
  b: number,
  c: string,
  scale: number = 1,
  c1?: string,
) {
  // 应用缩放
  const scaledX = x * scale
  const scaledY = y * scale
  const scaledR = r * scale

  ctx.setLineDash([0, 0])
  ctx.beginPath()
  ctx.LineWidth = b

  if (c1) {
    // 使用渐变色
    const gradient = ctx.createRadialGradient(scaledX, scaledY, scaledR)
    gradient.addColorStop(0, c)
    gradient.addColorStop(1, c1)
    ctx.strokeStyle = gradient
  } else {
    ctx.strokeStyle = c
  }

  ctx.arc(scaledX, scaledY, scaledR, 0, 2 * Math.PI)
  ctx.stroke()
  ctx.closePath()
  if (c) {
    ctx.fillStyle = c
    ctx.fill()
  }
}

/**
 * 绘制等边三角形
 * @param ctx Canvas上下文
 * @param x 重心坐标X
 * @param y 重心坐标Y
 * @param rotate 放置角度
 * @param b 边线粗度
 * @param c 线段颜色
 * @param fc 填充色（可选）
 * @param scale 缩放比例，默认为1
 * @param side 边长（可选，如果不提供则根据默认高度30计算）
 */
export function drawTriangle(
  ctx: any,
  x: number,
  y: number,
  rotate: number = 0,
  b: number,
  c: string,
  fc?: string,
  scale: number = 1,
  side?: number,
) {
  // 应用缩放
  const scaledX = x * scale
  const scaledY = y * scale

  const PI = Math.PI
  const sqrt3 = Math.sqrt(3)

  // 默认高度为30
  const defaultHeight = 30 * scale

  // 如果没有提供边长，则根据默认高度计算边长
  // 等边三角形的高 = (√3/2) * 边长，所以边长 = 高 * (2/√3)
  const scaledSide = side ? side * scale : defaultHeight * (2 / sqrt3)

  // 计算三角形中心到顶点的距离（高的1/3）
  const radius = (sqrt3 / 3) * scaledSide

  // 将角度转换为弧度
  const rotationRad = (rotate * PI) / 180

  // 原始顶点（未旋转），相对于中心点 (0, 0)
  const originalVertices = [
    { x: 0, y: -radius }, // 顶部顶点
    { x: -scaledSide / 2, y: radius / 2 }, // 左下顶点
    { x: scaledSide / 2, y: radius / 2 }, // 右下顶点
  ]

  // 应用旋转和平移
  const rotatedVertices = originalVertices.map((vertex) => {
    // 旋转
    const xRotated = vertex.x * Math.cos(rotationRad) - vertex.y * Math.sin(rotationRad)
    const yRotated = vertex.x * Math.sin(rotationRad) + vertex.y * Math.cos(rotationRad)

    // 平移回原位
    return { x: xRotated + scaledX, y: yRotated + scaledY }
  })

  // 绘制三角形
  ctx.beginPath()
  ctx.LineWidth = b
  ctx.strokeStyle = c

  ctx.moveTo(rotatedVertices[0].x, rotatedVertices[0].y)
  ctx.lineTo(rotatedVertices[1].x, rotatedVertices[1].y)
  ctx.lineTo(rotatedVertices[2].x, rotatedVertices[2].y)
  ctx.closePath()

  if (fc) {
    ctx.setFillStyle(fc)
    ctx.fill()
  }

  ctx.stroke()
}

/**
 * 绘制文字
 * @param ctx Canvas上下文
 * @param x 坐标X
 * @param y 坐标Y
 * @param txt 文本
 * @param s 字号
 * @param b 加粗
 * @param c 文字颜色
 * @param scale 缩放比例，默认为1
 */
export function drawText(
  ctx: any,
  x: number,
  y: number,
  txt: string,
  s: number,
  b: number,
  c: string,
  scale: number = 1,
) {
  // 应用缩放
  const scaledX = x * scale
  const scaledY = y * scale
  const scaledS = s * scale

  ctx.setFontSize(scaledS)
  ctx.setFillStyle(c)
  ctx.setTextBaseline('middle')
  ctx.setTextAlign('center')

  if (b > 0) {
    ctx.font = `bold ${scaledS}px sans-serif`
  } else {
    ctx.font = `${scaledS}px sans-serif`
  }

  ctx.fillText(txt, scaledX, scaledY)
}

/**
 * 绘制扇形
 * @param ctx Canvas上下文
 * @param x 圆心坐标X
 * @param y 圆心坐标Y
 * @param r 半径
 * @param a1 开始弧度
 * @param a2 结束弧度
 * @param da 扇形弧度
 * @param c 填充色
 * @param dx 文字坐标X
 * @param dy 文字坐标Y
 * @param dc 文字颜色
 * @param ds 文字大小
 * @param scale 缩放比例，默认为1
 * @param direction 绘制方向 默认true逆时针   false顺时针
 */
export function drawSector(
  ctx: any,
  x: number,
  y: number,
  r: number,
  a1: number,
  a2: number,
  da: number,
  c: string,
  dx: number,
  dy: number,
  ds: number = 12,
  dc: string,
  scale: number = 1,
  direction: boolean = true,
) {
  // 应用缩放
  const scaledX = x * scale
  const scaledY = y * scale
  const scaledR = r * scale
  const scaledDx = dx * scale
  const scaledDy = dy * scale

  ctx.beginPath()
  ctx.setFillStyle(c)
  ctx.moveTo(scaledX, scaledY)
  ctx.arc(scaledX, scaledY, scaledR, a1, a2, direction)
  ctx.fill()

  // 绘制文字
  ctx.setFontSize(ds * scale)
  ctx.setFillStyle(dc)
  ctx.fillText(da.toString(), scaledDx, scaledDy)
}

/**
 * 绘制铅锤线
 * @param ctx Canvas上下文
 * @param s 起点 {x, y}
 * @param e 结束点 {x, y}
 * @param b 线段粗度
 * @param c 填充色
 * @param c1 渐变色（可选）
 * @param img 图片地址
 * @param scale 缩放比例，默认为1
 */
/**
 * 绘制铅锤线
 * @param ctx Canvas上下文
 * @param s 起点 {x, y}
 * @param e 结束点 {x, y}
 * @param b 线段粗度
 * @param c 填充色
 * @param img 图片地址
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 * @param drawImmediately 是否立即调用draw方法，默认为true
 */
export function drawPlumbLine(
  ctx: any,
  s: Point,
  e: Point,
  b: number,
  c: string,
  img: string,
  c1?: string,
  scale: number = 1,
  drawImmediately: boolean = true,
) {
  // 绘制线段
  drawLine(ctx, s, e, b, c, c1, scale)

  // 如果有图片，则在终点绘制图片
  if (img) {
    // 应用缩放
    const scaledE = applyScale(e, scale)
    const imgSize = 20 * scale // 图片大小

    // 使用uni.getImageInfo获取图片信息
    uni.getImageInfo({
      src: img,
      success: (res) => {
        // 获取图片成功后绘制
        ctx.drawImage(res.path, scaledE.x - imgSize / 2, scaledE.y - imgSize / 2, imgSize, imgSize)

        // 调用draw方法更新画布
        if (drawImmediately && ctx.draw) {
          ctx.draw(true) // 保留之前的绘制内容
        }
      },
      fail: (err) => {
        console.error('加载图片失败:', err)

        // 即使图片加载失败，也应该更新画布以显示线段
        if (drawImmediately && ctx.draw) {
          ctx.draw(true)
        }
      },
    })
  } else if (drawImmediately && ctx.draw) {
    // 如果没有图片，但需要立即绘制，则直接调用draw
    ctx.draw(true)
  }
}

/**
 * 绘制贝塞尔曲线箭头（使用角度参数）
 * @param ctx Canvas上下文
 * @param start 起点 {x, y}
 * @param end 终点 {x, y}
 * @param angle 曲线弯曲的角度（度数，0表示直线，正值向上弯曲，负值向下弯曲）
 * @param curvature 曲线弯曲程度（0-1之间，值越大弯曲越明显）
 * @param b 线段粗度
 * @param isDashed 是否为虚线
 * @param size 箭头大小
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawBezierArrow(
  ctx: any,
  start: Point,
  end: Point,
  angle: number,
  curvature: number = 0.5,
  b: number = 2,
  isDashed: number = 0,
  size: number = 10,
  c: string = '#000000',
  scale: number = 1,
  c1?: string,
) {
  // 计算起点和终点之间的距离和中点
  const dx = end.x - start.x
  const dy = end.y - start.y
  const distance = Math.sqrt(dx * dx + dy * dy)

  // 计算起点到终点的角度（弧度）
  const lineAngle = Math.atan2(dy, dx)

  // 将输入角度转换为弧度
  const curveAngle = (angle * Math.PI) / 180

  // 计算控制点到直线的垂直距离
  const controlDistance = distance * curvature

  // 计算控制点位置（垂直于起点到终点的直线）
  const controlPoint: Point = {
    x:
      (start.x + end.x) / 2 +
      Math.cos(lineAngle + Math.PI / 2) * controlDistance * Math.sin(curveAngle),
    y:
      (start.y + end.y) / 2 +
      Math.sin(lineAngle + Math.PI / 2) * controlDistance * Math.sin(curveAngle),
  }

  // 调用原始的贝塞尔曲线箭头函数
  drawBezierArrowWithControlPoints(
    ctx,
    start,
    end,
    controlPoint,
    undefined,
    b,
    isDashed,
    size,
    c,
    c1,
    scale,
  )
}

/**
 * 绘制贝塞尔曲线箭头（使用控制点）
 * @param ctx Canvas上下文
 * @param start 起点 {x, y}
 * @param end 终点 {x, y}
 * @param controlPoint 控制点 {x, y}（二次贝塞尔曲线的控制点）
 * @param controlPoint2 第二控制点 {x, y}（可选，用于三次贝塞尔曲线）
 * @param b 线段粗度
 * @param isDashed 是否为虚线
 * @param size 箭头大小
 * @param c 线段颜色
 * @param c1 渐变色（可选）
 * @param scale 缩放比例，默认为1
 */
export function drawBezierArrowWithControlPoints(
  ctx: any,
  start: Point,
  end: Point,
  controlPoint: Point,
  controlPoint2?: Point,
  b: number = 2,
  isDashed: number = 0,
  size: number = 10,
  c: string = '#000000',
  c1?: string,
  scale: number = 1,
) {
  // 应用缩放
  const scaledStart = applyScale(start, scale)
  const scaledEnd = applyScale(end, scale)
  const scaledControlPoint = applyScale(controlPoint, scale)
  const scaledControlPoint2 = controlPoint2 ? applyScale(controlPoint2, scale) : undefined
  const scaledSize = size * scale

  // 绘制贝塞尔曲线
  ctx.beginPath()
  ctx.LineWidth = b

  // 设置虚线样式（如果需要）
  if (isDashed == 1) {
    ctx.setLineDash([2, 2], 0) // 设置虚线样式，线段长度5，间隙长度5
  } else {
    ctx.setLineDash([0, 0], 0)
  }

  if (c1) {
    // 使用渐变色
    const gradient = ctx.createLinearGradient(
      scaledStart.x,
      scaledStart.y,
      scaledEnd.x,
      scaledEnd.y,
    )
    gradient.addColorStop(0, c)
    gradient.addColorStop(1, c1)
    ctx.strokeStyle = gradient
  } else {
    ctx.strokeStyle = c
  }

  ctx.moveTo(scaledStart.x, scaledStart.y)

  if (scaledControlPoint2) {
    // 三次贝塞尔曲线
    ctx.bezierCurveTo(
      scaledControlPoint.x,
      scaledControlPoint.y,
      scaledControlPoint2.x,
      scaledControlPoint2.y,
      scaledEnd.x,
      scaledEnd.y,
    )
  } else {
    // 二次贝塞尔曲线
    ctx.quadraticCurveTo(scaledControlPoint.x, scaledControlPoint.y, scaledEnd.x, scaledEnd.y)
  }

  ctx.stroke()

  // 重置虚线样式
  if (isDashed) {
    ctx.setLineDash([0, 0], 0)
  }

  // 计算箭头方向（曲线终点处的切线方向）
  let tangentAngle

  if (scaledControlPoint2) {
    // 三次贝塞尔曲线的终点切线方向
    // 切线方向由最后一个控制点指向终点
    tangentAngle = Math.atan2(
      scaledEnd.y - scaledControlPoint2.y,
      scaledEnd.x - scaledControlPoint2.x,
    )
  } else {
    // 二次贝塞尔曲线的终点切线方向
    // 切线方向由控制点指向终点
    tangentAngle = Math.atan2(
      scaledEnd.y - scaledControlPoint.y,
      scaledEnd.x - scaledControlPoint.x,
    )
  }

  // 计算箭头两边的点
  const theta = (30 * Math.PI) / 180 // 箭头与线的夹角（弧度）

  // 使用线段终点作为箭头底边的中点
  const arrowTip = {
    x: scaledEnd.x + Math.cos(tangentAngle) * scaledSize,
    y: scaledEnd.y + Math.sin(tangentAngle) * scaledSize,
  } // 箭头尖端

  // 计算箭头底边的两个点（以终点为基准）
  const arrowBaseHalfWidth = scaledSize * Math.sin(theta) // 箭头底边一半的宽度

  // 计算底边方向（与切线垂直）
  const baseAngle = tangentAngle + Math.PI / 2

  // 计算底边两个顶点
  const arrowLeft = {
    x: scaledEnd.x + Math.cos(baseAngle) * arrowBaseHalfWidth,
    y: scaledEnd.y + Math.sin(baseAngle) * arrowBaseHalfWidth,
  }
  const arrowRight = {
    x: scaledEnd.x - Math.cos(baseAngle) * arrowBaseHalfWidth,
    y: scaledEnd.y - Math.sin(baseAngle) * arrowBaseHalfWidth,
  }

  // 绘制箭头
  ctx.beginPath()
  ctx.setFillStyle(c1 || c) // 使用渐变色或主色
  ctx.moveTo(arrowTip.x, arrowTip.y) // 箭头尖端
  ctx.lineTo(arrowLeft.x, arrowLeft.y) // 左侧点
  ctx.lineTo(arrowRight.x, arrowRight.y) // 右侧点
  ctx.closePath()
  ctx.fill()
}
